// 类装饰器
function dc(n: number) {
  console.log("dc enter:", "n is", n);
  return function (target): void {
    console.log("dc() enter:", "target is", target);
  };
}

// 方法装饰器 1
function df() {
  console.log("df enter");
  // descriptor: { value: [Function], writable: boolean, enumerable: boolean, configurable: boolean }
  return (target, propertyKey: string, descriptor: PropertyDescriptor): void =>
    console.log("df() enter:", "target is", target, ", propertyKey is", propertyKey, ", descriptor is", descriptor);
}

// 方法装饰器 2
function df2() {
  console.log("df2 enter");
  return (target, propertyKey: string, descriptor: PropertyDescriptor): void =>
    console.log("df2() enter:", "target is", target, ", propertyKey is", propertyKey, ", descriptor is", descriptor);
}

// 参数装饰器
function da(type: string) {
  console.log("da enter:", "type is", type);
  return (target, name: string, index: number): void =>
    console.log("da() enter:", " target is", target, ", name is", name, ", index is", index);
}

// 属性装饰器
function dp(target, propertyKey: string) {
  console.log("dp() enter:", "target is", target, ", propertyKey is", propertyKey);
  if (delete target[propertyKey]) {
    Object.defineProperty(target, propertyKey, {
      get: (): string => {
        console.log(`dp(): get(): get ${propertyKey} as "${target["_" + propertyKey]}"`);
        return target["_" + propertyKey];
      },
      set: function (c: string): void {
        console.log(`dp(): set(): set ${propertyKey} to "${c}"`);
        target["_" + propertyKey] = c;
      },
    });
  }
}

// 访问器装饰器
function dv(num: number) {
  console.log("dv enter:", "num is", num);
  return (target, propertyKey: string, descriptor: PropertyDescriptor) =>
    console.log("dv() enter:", "target is", target, ", propertyKey is", propertyKey, ", descriptor is", descriptor);
}

@dc(100)
class C {
  @dp
  _label: string;
  constructor(label: string) {
    console.log("C.constructor enter");
    this._label = label;
  }
  @df()
  @df2()
  cf(@da("string") text: string) {
    console.log("cf enter with text:", text);
    console.log("c labeled:", this._label);
  }
  @dv(200)
  get label(): string {
    return this._label;
  }
}

const c = new C("I'm c");
c.cf("start");

export {};
